import typing
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox
import sys
from ui.Ui_net_assit_widget import Ui_Form
import socket
import threading
from utils import get_local_ip, decode_data
from datetime import datetime


class MyWidget(QWidget):
    # 定义一个信号，用于从工作线程传递数据到主线程
    data_received = QtCore.pyqtSignal(str)
    connection_status_changed = QtCore.pyqtSignal(bool)  # 新增信号，用于连接状态变化
    server_status_changed = QtCore.pyqtSignal(bool)  # 新增信号，用于服务器状态变化
    
    def __init__(self, parent=None):
        super().__init__()
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.tcp_socket = None
        self.is_connected = False  # 客户端连接状态标志
        self.is_server_running = False  # 服务器运行状态标志
        self.server_socket = None  # 服务器socket
        self.client_sockets = {}  # 客户端连接socket字典，键为客户端地址，值为socket对象
        self.client_threads = {}  # 客户端处理线程字典
        self.lock = threading.Lock()  # 线程锁，用于保护共享资源
        self.init_ui()
        
        # 连接信号到槽函数
        self.data_received.connect(self.update_recv_text)
        self.connection_status_changed.connect(self.update_connect_btn)  # 连接状态变化信号
        self.server_status_changed.connect(self.update_server_btn)  # 服务器状态变化信号
    
    def on_send_clicked(self):
        # 判断当前模式
        current_mode = self.ui.cb_mode.currentIndex()
        
        if current_mode == 0:  # 客户端模式
            # 判断是否已连接
            if self.tcp_socket is None or not self.is_connected:
                print("请先连接服务器")
                self.ui.edit_recv.append("错误: 请先连接服务器")
                return
            text = self.ui.edit_send.toPlainText()
            if not text:
                print("发送内容为空")
                return
                
            print("发送数据:", text)
            try:
                self.tcp_socket.send(text.encode("GBK"))
            except Exception as e:
                print("发送失败:", e)
                self.ui.edit_recv.append(f"发送失败: {str(e)}")
        
        elif current_mode == 1:  # 服务器模式
            # 判断是否有客户端连接
            if not self.client_sockets:
                print("没有客户端连接")
                self.ui.edit_recv.append("错误: 没有客户端连接")
                return
            text = self.ui.edit_send.toPlainText()
            if not text:
                print("发送内容为空")
                return
                
            print("发送数据到所有客户端:", text)
            try:
                # 向所有连接的客户端发送数据
                with self.lock:
                    disconnected_clients = []
                    for addr, client_socket in self.client_sockets.items():
                        try:
                            client_socket.send(text.encode("GBK"))
                        except Exception as e:
                            print(f"向客户端 {addr} 发送失败: {e}")
                            disconnected_clients.append(addr)
                    
                    # 移除断开连接的客户端
                    for addr in disconnected_clients:
                        self.remove_client(addr)
                        
            except Exception as e:
                print("发送失败:", e)
                self.ui.edit_recv.append(f"发送失败: {str(e)}")
    
    def on_mode_changed(self):
        index = self.ui.cb_mode.currentIndex()
        if index == 0:
            self.ui.label_ip.setText("服务器IP:")
            self.ui.Label_port.setText("服务器端口:")
            # 更新按钮状态
            self.update_connect_btn(self.is_connected)
        else:
            self.ui.label_ip.setText("本地IP:")
            self.ui.Label_port.setText("本地端口:")
            # 更新按钮状态
            self.update_server_btn(self.is_server_running)
    
    def init_ui(self):
        self.ui.btn_connect.clicked.connect(self.on_button_clicked)
        self.ui.edit_target_ip.setText("127.0.0.1")
        self.ui.edit_target_port.setText("8080")
        local_ips = get_local_ip()
        self.ui.cb_local_ip.addItems(local_ips)
        self.ui.pushButton_2.clicked.connect(self.on_send_clicked)
        self.ui.cb_mode.currentIndexChanged.connect(self.on_mode_changed)
        # 初始化按钮状态
        self.update_connect_btn(False)
        self.update_server_btn(False)
    
    def update_recv_text(self, text):
        """在主线程中更新接收文本框"""
        self.ui.edit_recv.append(text)
    
    @QtCore.pyqtSlot(str, str)
    def update_ui_after_connect(self, local_ip, local_port):
        """在主线程中更新UI"""
        self.ui.cb_local_ip.setCurrentIndex(self.ui.cb_local_ip.findText(local_ip))
        self.ui.edit_local_port.setText(local_port)
    
    def run_tcp_client(self, target_ip, target_port):
        try:
            self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_socket.settimeout(5)  # 设置超时时间
            
            # 尝试连接
            self.tcp_socket.connect((target_ip, int(target_port)))
            print("服务器连接成功")
            self.is_connected = True
            self.connection_status_changed.emit(True)  # 发送连接状态变化信号
            
            # 获取本地分配的端口号
            local_ip, local_port = self.tcp_socket.getsockname()
            # 使用信号更新UI，而不是直接操作
            QtCore.QMetaObject.invokeMethod(self, "update_ui_after_connect", 
                                           QtCore.Qt.QueuedConnection,
                                           QtCore.Q_ARG(str, local_ip),
                                           QtCore.Q_ARG(str, str(local_port)))
            
            # 接收数据循环
            while self.is_connected:
                try:
                    bytes_data = self.tcp_socket.recv(1024)
                    if bytes_data:
                        # 在工作线程中准备数据，但通过信号发送到主线程更新UI
                        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                        decoded_data = decode_data(bytes_data)
                        formatted_data = f"[{current_time}] {decoded_data}"
                        self.data_received.emit(formatted_data)
                    else:
                        break
                except socket.timeout:
                    # 超时是正常的，继续循环
                    continue
                except Exception as e:
                    print("接收数据错误:", e)
                    self.data_received.emit(f"接收错误: {str(e)}")
                    break
                    
        except socket.error as e:
            error_msg = f"连接失败: {str(e)}"
            print(error_msg)
            self.data_received.emit(error_msg)
        except Exception as e:
            error_msg = f"发生未知错误: {str(e)}"
            print(error_msg)
            self.data_received.emit(error_msg)
        finally:
            self.is_connected = False
            self.connection_status_changed.emit(False)  # 发送连接状态变化信号
            if self.tcp_socket is not None:
                self.tcp_socket.close()
                self.tcp_socket = None
                print("连接已关闭")
    
    def handle_client(self):
        if self.is_connected:
            print("断开连接")
            self.is_connected = False
            if self.tcp_socket is not None:
                self.tcp_socket.close()
                self.tcp_socket = None
            self.connection_status_changed.emit(False)
            return
            
        target_ip = self.ui.edit_target_ip.text()
        target_port = self.ui.edit_target_port.text()
        print("Target IP:", target_ip)
        print("Target Port:", target_port)
        if target_ip == "" or target_port == "":
            print("请输入目标ip和端口")
            self.ui.edit_recv.append("错误: 请输入目标IP和端口")
            return
        
        # 清空之前的信息
        self.ui.edit_recv.clear()
        self.ui.edit_recv.append(f"正在连接 {target_ip}:{target_port}...")
        
        # 启动连接线程
        threading.Thread(target=self.run_tcp_client, args=(target_ip, target_port), daemon=True).start()
    
    def handle_client_connection(self, client_socket, client_addr):
        """处理单个客户端连接的线程函数"""
        try:
            # 向客户端发送欢迎消息
            welcome_msg = f"欢迎连接服务器，您的地址是: {client_addr}"
            client_socket.send(welcome_msg.encode("GBK"))
            self.data_received.emit(f"客户端 {client_addr} 已连接")
            
            # 接收客户端数据
            while self.is_server_running and client_socket:
                try:
                    bytes_data = client_socket.recv(1024)
                    if bytes_data:
                        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                        decoded_data = decode_data(bytes_data)
                        formatted_data = f"[{current_time}] 客户端 {client_addr}: {decoded_data}"
                        self.data_received.emit(formatted_data)
                    else:
                        # 客户端断开连接
                        break
                except socket.timeout:
                    continue
                except Exception as e:
                    print(f"从客户端 {client_addr} 接收数据错误: {e}")
                    break
            
        except Exception as e:
            print(f"处理客户端 {client_addr} 连接错误: {e}")
        finally:
            # 移除客户端
            self.remove_client(client_addr)
            client_socket.close()
            print(f"客户端 {client_addr} 连接已关闭")
            self.data_received.emit(f"客户端 {client_addr} 已断开连接")
    
    def remove_client(self, client_addr):
        """移除客户端连接"""
        with self.lock:
            if client_addr in self.client_sockets:
                del self.client_sockets[client_addr]
            if client_addr in self.client_threads:
                del self.client_threads[client_addr]
    
    def run_tcp_server(self, server_ip, server_port):
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((server_ip, int(server_port)))
            self.server_socket.listen(128)
            self.server_socket.settimeout(1)  # 设置超时以便检查停止标志
            
            print(f"服务器启动成功，监听 {server_ip}:{server_port}")
            self.data_received.emit(f"服务器启动成功，监听 {server_ip}:{server_port}")
            
            while self.is_server_running:
                try:
                    client_socket, client_addr = self.server_socket.accept()
                    client_socket.settimeout(1)
                    
                    print(f"客户端连接: {client_addr}")
                    
                    # 将客户端添加到字典中
                    with self.lock:
                        self.client_sockets[client_addr] = client_socket
                    
                    # 创建线程处理客户端连接
                    client_thread = threading.Thread(
                        target=self.handle_client_connection, 
                        args=(client_socket, client_addr),
                        daemon=True
                    )
                    client_thread.start()
                    
                    # 保存线程引用
                    with self.lock:
                        self.client_threads[client_addr] = client_thread
                        
                except socket.timeout:
                    continue
                except Exception as e:
                    if self.is_server_running:
                        print(f"接受连接错误: {e}")
                        self.data_received.emit(f"接受连接错误: {str(e)}")
                    break
                    
        except Exception as e:
            error_msg = f"服务器错误: {str(e)}"
            print(error_msg)
            self.data_received.emit(error_msg)
        finally:
            # 清理资源
            with self.lock:
                # 关闭所有客户端连接
                for client_socket in self.client_sockets.values():
                    try:
                        client_socket.close()
                    except:
                        pass
                self.client_sockets.clear()
                self.client_threads.clear()
                
            if self.server_socket:
                self.server_socket.close()
                self.server_socket = None
            self.is_server_running = False
            self.server_status_changed.emit(False)
            print("服务器已停止")
            self.data_received.emit("服务器已停止")
        
    def handle_server(self):
        if self.is_server_running:
            print("停止服务器")
            self.is_server_running = False
            if self.server_socket:
                self.server_socket.close()
                self.server_socket = None
            self.server_status_changed.emit(False)
            return
            
        server_ip = self.ui.cb_local_ip.currentText()
        server_port = self.ui.edit_target_port.text()
        
        if server_port == "":
            QMessageBox.warning(self, "警告", "请输入端口号")
            return
            
        # 清空之前的信息
        self.ui.edit_recv.clear()
        self.ui.edit_recv.append(f"启动服务器 {server_ip}:{server_port}...")
        
        self.is_server_running = True
        self.server_status_changed.emit(True)
        
        # 启动服务器线程
        threading.Thread(target=self.run_tcp_server, args=(server_ip, server_port), daemon=True).start()
    
    def on_button_clicked(self):
        current_mode = self.ui.cb_mode.currentIndex()
        if current_mode == 0:  # 客户端模式
            self.handle_client()
        elif current_mode == 1:  # 服务器模式
            self.handle_server()
        
    @QtCore.pyqtSlot(bool)
    def update_connect_btn(self, connected):
        """更新连接按钮文字（客户端模式）"""
        if connected:
            self.ui.btn_connect.setText("断开连接(已连接)")
        else:
            self.ui.btn_connect.setText("连接网络")
    
    @QtCore.pyqtSlot(bool)
    def update_server_btn(self, running):
        """更新连接按钮文字（服务器模式）"""
        current_mode = self.ui.cb_mode.currentIndex()
        if current_mode == 1:  # 只在服务器模式下更新
            if running:
                self.ui.btn_connect.setText("停止服务器(已启动)")
            else:
                self.ui.btn_connect.setText("启动服务器")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())